
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Django 中的自定义验证 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../../_static/jquery.js"></script>
    <script type="text/javascript" src="../../_static/underscore.js"></script>
    <script type="text/javascript" src="../../_static/doctools.js"></script>
    <script type="text/javascript" src="../../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../../genindex.html" />
    <link rel="search" title="搜索" href="../../search.html" />
    <link rel="next" title="Django 缓存框架" href="../cache.html" />
    <link rel="prev" title="Django中的密码管理" href="passwords.html" />



 
<script src="../../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);</script>

  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../../index.html">Home</a>  |
        <a title="Table of contents" href="../../contents.html">Table of contents</a>  |
        <a title="Global index" href="../../genindex.html">Index</a>  |
        <a title="Module index" href="../../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="passwords.html" title="Django中的密码管理">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="../cache.html" title="Django 缓存框架">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="topics-auth-customizing">
            
  <div class="section" id="s-customizing-authentication-in-django">
<span id="customizing-authentication-in-django"></span><h1>Django 中的自定义验证<a class="headerlink" href="#customizing-authentication-in-django" title="永久链接至标题">¶</a></h1>
<p>Django 自带的身份验证已经足够满足大多数常见的情况，但你可能有一些需求没有被开箱即用的默认值所满足。在你的项目中定制身份验证需要了解所提供系统的哪些点是可扩展或可替换的。本文档详细介绍了如何定制认证系统。</p>
<p>当用户模型中存储的用户名和密码需要对一个不同于 Django 默认服务验证时，<a class="reference internal" href="#authentication-backends"><span class="std std-ref">认证后端</span></a> 提供了一个可扩展的系统。</p>
<p>你可以给你的模型 <a class="reference internal" href="#custom-permissions"><span class="std std-ref">自定义权限</span></a> 并且可以通过 Django 的授权系统检查。</p>
<p>你可以 <a class="reference internal" href="#extending-user"><span class="std std-ref">扩展</span></a> 默认的 <code class="docutils literal notranslate"><span class="pre">User</span></code> 模型，或者完全自定义一个模型进行 <a class="reference internal" href="#auth-custom-user"><span class="std std-ref">替换</span></a></p>
<div class="section" id="s-other-authentication-sources">
<span id="s-authentication-backends"></span><span id="other-authentication-sources"></span><span id="authentication-backends"></span><h2>其它认证资源<a class="headerlink" href="#other-authentication-sources" title="永久链接至标题">¶</a></h2>
<p>有时候你需要连接到其他认证源——一个包含用户名及密码的源或者认证方法。</p>
<p>例如，你的公司可能已经有了一个 LDAP 配置，为每个员工存储了一个用户名和密码。如果用户在 LDAP 和基于 Django 的应用程序中分别有不同的账户，那么对于网络管理员和用户本身来说都是一件很麻烦的事情。</p>
<p>所以，为了处理这样的情况，Django 认证系统让你可以插入其他认证源。你可以覆盖 Django 默认的基于数据库的方案，也可以将默认系统与其他系统串联使用。</p>
<p>参见 <a class="reference internal" href="../../ref/contrib/auth.html#authentication-backends-reference"><span class="std std-ref">认证后端参考</span></a>，了解 Django 所包含的认证后端的信息。</p>
<div class="section" id="s-specifying-authentication-backends">
<span id="specifying-authentication-backends"></span><h3>指定认证后端<a class="headerlink" href="#specifying-authentication-backends" title="永久链接至标题">¶</a></h3>
<p>在幕后，Django 维护了一个 “认证后端” 列表，用于检查认证。当有人调用 <a class="reference internal" href="default.html#django.contrib.auth.authenticate" title="django.contrib.auth.authenticate"><code class="xref py py-func docutils literal notranslate"><span class="pre">django.contrib.auth.authenticate()</span></code></a> ——就像 <a class="reference internal" href="default.html#how-to-log-a-user-in"><span class="std std-ref">如何登录用户</span></a> 中描述的那样——Django 会尝试对所有的认证后端进行认证。如果第一个认证方法失败，Django 就尝试第二个，以此类推，直到所有后端都尝试过。</p>
<p>要使用的认证后端列表在 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTHENTICATION_BACKENDS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTHENTICATION_BACKENDS</span></code></a> 配置中指定。这应该是一个指向知道如何验证的 Python 类的 Python 路径名列表。这些类可以是 Python 路径上的任何地方。</p>
<p>默认情况下，<a class="reference internal" href="../../ref/settings.html#std:setting-AUTHENTICATION_BACKENDS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTHENTICATION_BACKENDS</span></code></a> 配置为：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="s1">&#39;django.contrib.auth.backends.ModelBackend&#39;</span><span class="p">]</span>
</pre></div>
</div>
<p>Django 的默认后台只检查其数据库和内置权限，并不提供任何登录限制机制来防止暴力登录攻击。如果需要抵制暴力登录攻击，需要自己在后台实现登录限制机制，或者使用 Web 服务器提供的保护机制。</p>
<p><a class="reference internal" href="../../ref/settings.html#std:setting-AUTHENTICATION_BACKENDS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTHENTICATION_BACKENDS</span></code></a> 的顺序很重要，所以如果同一个用户名和密码在多个后端都有效，Django 会在第一个正向匹配时停止处理。</p>
<p>如果一个后端抛出 <a class="reference internal" href="../../ref/exceptions.html#django.core.exceptions.PermissionDenied" title="django.core.exceptions.PermissionDenied"><code class="xref py py-class docutils literal notranslate"><span class="pre">PermissionDenied</span></code></a> 异常，则验证流程立马终止，Django 不会继续检查其后的后端。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">一旦用户进行了身份认证，Django 就会在用户的会话中存储哪个后端对用户进行了身份验证，并在该会话期间，每当需要访问当前已身份认证的用户时，就会重新使用同一个后端。这实际上意味着认证源是以每个会话为基础进行缓存的，所以如果你改变了 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTHENTICATION_BACKENDS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTHENTICATION_BACKENDS</span></code></a>，如果你需要强制用户使用不同的方法重新认证，你就需要清除会话数据。一个简单的方法就是执行 <code class="docutils literal notranslate"><span class="pre">Session.objects.all().delete()</span></code>。</p>
</div>
</div>
<div class="section" id="s-writing-an-authentication-backend">
<span id="writing-an-authentication-backend"></span><h3>编写一个认证后端<a class="headerlink" href="#writing-an-authentication-backend" title="永久链接至标题">¶</a></h3>
<p>认证后端是一个类，它实现了两个必要的方法：<code class="docutils literal notranslate"><span class="pre">get_user(user_id)</span></code> 和 <code class="docutils literal notranslate"><span class="pre">authenticate(request,</span> <span class="pre">**credentials)</span></code>，以及一组可选的与权限相关的 <a class="reference internal" href="#authorization-methods"><span class="std std-ref">认证方法</span></a>。</p>
<p><code class="docutils literal notranslate"><span class="pre">get_user</span></code> 方法接收一个 <code class="docutils literal notranslate"><span class="pre">user_id</span></code> ——可以是用户名、数据库 ID 或其他什么，但必须是用户对象的主键——然后返回一个用户对象或 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p>
<p><code class="docutils literal notranslate"><span class="pre">authenticate</span></code> 方法采用 <code class="docutils literal notranslate"><span class="pre">request</span></code> 参数和证书作为关键字参数。大多数情况下，它看起来像这样：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.auth.backends</span> <span class="kn">import</span> <span class="n">BaseBackend</span>

<span class="k">class</span> <span class="nc">MyBackend</span><span class="p">(</span><span class="n">BaseBackend</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">authenticate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="c1"># Check the username/password and return a user.</span>
        <span class="o">...</span>
</pre></div>
</div>
<p>但它也可以认证一个令牌，比如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.auth.backends</span> <span class="kn">import</span> <span class="n">BaseBackend</span>

<span class="k">class</span> <span class="nc">MyBackend</span><span class="p">(</span><span class="n">BaseBackend</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">authenticate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">token</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="c1"># Check the token and return a user.</span>
        <span class="o">...</span>
</pre></div>
</div>
<p>无论哪种方式，<code class="docutils literal notranslate"><span class="pre">authenticate()</span></code> 应该检查它所得到的凭证，如果凭证有效，则返回一个与这些凭证相匹配的用户对象。如果无效，则应返回 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p>
<p><code class="docutils literal notranslate"><span class="pre">request</span></code> 是一个 <a class="reference internal" href="../../ref/request-response.html#django.http.HttpRequest" title="django.http.HttpRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">HttpRequest</span></code></a>，如果没有提供给 <a class="reference internal" href="default.html#django.contrib.auth.authenticate" title="django.contrib.auth.authenticate"><code class="xref py py-func docutils literal notranslate"><span class="pre">authenticate()</span></code></a> （将其传递给后端），则可能是 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p>
<p>Django admin 与 Django <a class="reference internal" href="default.html#user-objects"><span class="std std-ref">User 对象</span></a> 紧密耦合。处理这个问题的最好方法是为每个存在于后台的用户创建一个 Django <code class="docutils literal notranslate"><span class="pre">User</span></code> 对象（例如，在你的 LDAP 目录中，你的外部 SQL 数据库中，等等），你可以提前写一个脚本来完成这个任务，或者你的 <code class="docutils literal notranslate"><span class="pre">authenticate</span></code> 方法可以在用户第一次登录时完成。</p>
<p>下面是一个后端实例，它可以根据 <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> 文件中定义的用户名和密码变量进行验证，并在用户第一次验证时创建一个 Django <code class="docutils literal notranslate"><span class="pre">User</span></code> 对象：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.backends</span> <span class="kn">import</span> <span class="n">BaseBackend</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.hashers</span> <span class="kn">import</span> <span class="n">check_password</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">User</span>

<span class="k">class</span> <span class="nc">SettingsBackend</span><span class="p">(</span><span class="n">BaseBackend</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.</span>

<span class="sd">    Use the login name and a hash of the password. For example:</span>

<span class="sd">    ADMIN_LOGIN = &#39;admin&#39;</span>
<span class="sd">    ADMIN_PASSWORD = &#39;pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M=&#39;</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">authenticate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="n">login_valid</span> <span class="o">=</span> <span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">ADMIN_LOGIN</span> <span class="o">==</span> <span class="n">username</span><span class="p">)</span>
        <span class="n">pwd_valid</span> <span class="o">=</span> <span class="n">check_password</span><span class="p">(</span><span class="n">password</span><span class="p">,</span> <span class="n">settings</span><span class="o">.</span><span class="n">ADMIN_PASSWORD</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">login_valid</span> <span class="ow">and</span> <span class="n">pwd_valid</span><span class="p">:</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">username</span><span class="p">)</span>
            <span class="k">except</span> <span class="n">User</span><span class="o">.</span><span class="n">DoesNotExist</span><span class="p">:</span>
                <span class="c1"># Create a new user. There&#39;s no need to set a password</span>
                <span class="c1"># because only the password from settings.py is checked.</span>
                <span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">username</span><span class="p">)</span>
                <span class="n">user</span><span class="o">.</span><span class="n">is_staff</span> <span class="o">=</span> <span class="kc">True</span>
                <span class="n">user</span><span class="o">.</span><span class="n">is_superuser</span> <span class="o">=</span> <span class="kc">True</span>
                <span class="n">user</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">user</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="k">def</span> <span class="nf">get_user</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user_id</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="n">user_id</span><span class="p">)</span>
        <span class="k">except</span> <span class="n">User</span><span class="o">.</span><span class="n">DoesNotExist</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>
</pre></div>
</div>
</div>
<div class="section" id="s-handling-authorization-in-custom-backends">
<span id="s-authorization-methods"></span><span id="handling-authorization-in-custom-backends"></span><span id="authorization-methods"></span><h3>在自定义后端处理认证<a class="headerlink" href="#handling-authorization-in-custom-backends" title="永久链接至标题">¶</a></h3>
<p>自定义的认证后端可以提供他们自己的权限。</p>
<p>用户模型和它的管理器会把权限查找函数（<a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.get_user_permissions" title="django.contrib.auth.models.User.get_user_permissions"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_user_permissions()</span></code></a>、<a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.get_group_permissions" title="django.contrib.auth.models.User.get_group_permissions"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_group_permissions()</span></code></a>、<a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.get_all_permissions" title="django.contrib.auth.models.User.get_all_permissions"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_all_permissions()</span></code></a>、<a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.has_perm" title="django.contrib.auth.models.User.has_perm"><code class="xref py py-meth docutils literal notranslate"><span class="pre">has_perm()</span></code></a>、<a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.has_module_perms" title="django.contrib.auth.models.User.has_module_perms"><code class="xref py py-meth docutils literal notranslate"><span class="pre">has_module_perms()</span></code></a> 和 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.UserManager.with_perm" title="django.contrib.auth.models.UserManager.with_perm"><code class="xref py py-meth docutils literal notranslate"><span class="pre">with_perm()</span></code></a>）委托给任何实现了这些函数的认证后端。</p>
<p>用户所拥有的权限将是所有验证后端返回的所有权限的一个超集。也就是说，如果任何后端之一将一个权限赋予了用户，那么 Django 最终也将该权限赋予这个用户。</p>
<p>如果后端在 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.has_perm" title="django.contrib.auth.models.User.has_perm"><code class="xref py py-meth docutils literal notranslate"><span class="pre">has_perm()</span></code></a> 或 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.has_module_perms" title="django.contrib.auth.models.User.has_module_perms"><code class="xref py py-meth docutils literal notranslate"><span class="pre">has_module_perms()</span></code></a> 中引发 <a class="reference internal" href="../../ref/exceptions.html#django.core.exceptions.PermissionDenied" title="django.core.exceptions.PermissionDenied"><code class="xref py py-class docutils literal notranslate"><span class="pre">PermissionDenied</span></code></a> 异常，认证就会立即失败，Django 也不会检查后面的后端。</p>
<p>后端可以像这样为管理员实现权限：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.auth.backends</span> <span class="kn">import</span> <span class="n">BaseBackend</span>

<span class="k">class</span> <span class="nc">MagicAdminBackend</span><span class="p">(</span><span class="n">BaseBackend</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">has_perm</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user_obj</span><span class="p">,</span> <span class="n">perm</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">user_obj</span><span class="o">.</span><span class="n">username</span> <span class="o">==</span> <span class="n">settings</span><span class="o">.</span><span class="n">ADMIN_LOGIN</span>
</pre></div>
</div>
<p>这就给了上例中授予访问权限的用户全部权限。请注意，除了给相关的 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">django.contrib.auth.models.User</span></code></a> 函数提供相同的参数外，后台的认证函数都以用户对象（可能是一个匿名用户）作为参数。</p>
<p>一个完整的鉴权实现可以在 <a class="reference external" href="https://github.com/django/django/blob/main/django/contrib/auth/backends.py">django/contrib/auth/backends.py</a> 的 <code class="docutils literal notranslate"><span class="pre">ModelBackend</span></code> 里找到，这是默认的后端，并且在大多数时候会查询 <code class="docutils literal notranslate"><span class="pre">auth_permission</span></code> 表。</p>
<div class="section" id="s-authorization-for-anonymous-users">
<span id="s-anonymous-auth"></span><span id="authorization-for-anonymous-users"></span><span id="anonymous-auth"></span><h4>匿名用户的授权<a class="headerlink" href="#authorization-for-anonymous-users" title="永久链接至标题">¶</a></h4>
<p>匿名用户是指那些没有验证过的用户，也就是说，他们没有提供任何有效的验证信息。然而，这并不一定意味着他们就无权做任何事。在最基本的层面上，大多数站点允许匿名用户浏览大部分页面，而且很多站点也允许匿名评论。</p>
<p>Django 的权限框架没有一个地方可以存储匿名用户的权限。但是，传递给认证后台的用户对象可以是一个 <code class="xref py py-class docutils literal notranslate"><span class="pre">django.contrib.uth.models.AnonymousUser</span></code> 对象，允许后台为匿名用户指定自定义的授权行为。这对于可重用应用的作者来说特别有用，他们可以将所有的授权问题委托给认证后端，而不是需要配置，例如，控制匿名访问。</p>
</div>
<div class="section" id="s-authorization-for-inactive-users">
<span id="s-inactive-auth"></span><span id="authorization-for-inactive-users"></span><span id="inactive-auth"></span><h4>非激活用户认证<a class="headerlink" href="#authorization-for-inactive-users" title="永久链接至标题">¶</a></h4>
<p>非激活用户是指 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_active" title="django.contrib.auth.models.User.is_active"><code class="xref py py-attr docutils literal notranslate"><span class="pre">is_active</span></code></a> 字段设置为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 的用户。<a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.backends.ModelBackend" title="django.contrib.auth.backends.ModelBackend"><code class="xref py py-class docutils literal notranslate"><span class="pre">ModelBackend</span></code></a> 和 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.backends.RemoteUserBackend" title="django.contrib.auth.backends.RemoteUserBackend"><code class="xref py py-class docutils literal notranslate"><span class="pre">RemoteUserBackend</span></code></a> 认证后端禁止这些用户进行认证。如果一个自定义用户模型没有 <a class="reference internal" href="#django.contrib.auth.models.CustomUser.is_active" title="django.contrib.auth.models.CustomUser.is_active"><code class="xref py py-attr docutils literal notranslate"><span class="pre">is_active</span></code></a> 字段，那么所有用户都将被允许认证。</p>
<p>如果你想让非激活用户进行身份认证，可以使用 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.backends.AllowAllUsersModelBackend" title="django.contrib.auth.backends.AllowAllUsersModelBackend"><code class="xref py py-class docutils literal notranslate"><span class="pre">AllowAllUsersModelBackend</span></code></a> 或 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.backends.AllowAllUsersRemoteUserBackend" title="django.contrib.auth.backends.AllowAllUsersRemoteUserBackend"><code class="xref py py-class docutils literal notranslate"><span class="pre">AllowAllUsersRemoteUserBackend</span></code></a>。</p>
<p>权限系统中对匿名用户的支持，可以实现匿名用户有权限做某事，而非激活的认证用户没有权限的场景。</p>
<p>不要忘记在自己的后端权限方法中测试用户的 <code class="docutils literal notranslate"><span class="pre">is_active</span></code> 属性。</p>
</div>
<div class="section" id="s-handling-object-permissions">
<span id="handling-object-permissions"></span><h4>处理对象权限<a class="headerlink" href="#handling-object-permissions" title="永久链接至标题">¶</a></h4>
<p>Django 的权限框架有一个对象权限的基础，尽管在核心中没有实现。这意味着对对象权限的检查总是返回 <code class="docutils literal notranslate"><span class="pre">False</span></code> 或一个空列表（取决于所执行的检查）。认证后端将为每个与对象相关的授权方法接收关键字参数 <code class="docutils literal notranslate"><span class="pre">obj</span></code> 和 <code class="docutils literal notranslate"><span class="pre">user_obj</span></code>，并可以适当返回对象级别的权限。</p>
</div>
</div>
</div>
<div class="section" id="s-custom-permissions">
<span id="s-id1"></span><span id="custom-permissions"></span><span id="id1"></span><h2>自定义权限<a class="headerlink" href="#custom-permissions" title="永久链接至标题">¶</a></h2>
<p>要为给定的模型对象创建自定义权限，使用 <code class="docutils literal notranslate"><span class="pre">permissions</span></code> <a class="reference internal" href="../db/models.html#meta-options"><span class="std std-ref">模型 Meta 属性</span></a>。</p>
<p>这个 <code class="docutils literal notranslate"><span class="pre">Task</span></code> 模型创建了两个自定义权限，即用户可以或不可以对 <code class="docutils literal notranslate"><span class="pre">Task</span></code> 实例进行的操作，具体到你的应用程序：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Task</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
        <span class="n">permissions</span> <span class="o">=</span> <span class="p">[</span>
            <span class="p">(</span><span class="s2">&quot;change_task_status&quot;</span><span class="p">,</span> <span class="s2">&quot;Can change the status of tasks&quot;</span><span class="p">),</span>
            <span class="p">(</span><span class="s2">&quot;close_task&quot;</span><span class="p">,</span> <span class="s2">&quot;Can remove a task by setting its status as closed&quot;</span><span class="p">),</span>
        <span class="p">]</span>
</pre></div>
</div>
<p>这样做的唯一作用就是当你运行 <a class="reference internal" href="../../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">manage.py</span> <span class="pre">migrate</span></code></a> 时，创建这些额外的权限（创建权限的函数连接到 <a class="reference internal" href="../../ref/signals.html#django.db.models.signals.post_migrate" title="django.db.models.signals.post_migrate"><code class="xref py py-data docutils literal notranslate"><span class="pre">post_migrate</span></code></a> 信号）。你的代码负责在用户试图访问应用程序提供的功能（改变任务状态或关闭任务）时检查这些权限的值。 继续上面的例子，下面检查用户是否可以关闭任务：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span><span class="o">.</span><span class="n">has_perm</span><span class="p">(</span><span class="s1">&#39;app.close_task&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-extending-the-existing-user-model">
<span id="s-extending-user"></span><span id="extending-the-existing-user-model"></span><span id="extending-user"></span><h2>扩展现有的 <code class="docutils literal notranslate"><span class="pre">User</span></code> 模型<a class="headerlink" href="#extending-the-existing-user-model" title="永久链接至标题">¶</a></h2>
<p>有两种方法可以扩展默认的 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 模型，而不用替换自己的模型。如果你需要的是纯粹的行为改变，而不需要改变数据库中存储的内容，你可以基于 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 创建一个 <a class="reference internal" href="../db/models.html#proxy-models"><span class="std std-ref">代理模型</span></a>。这允许代理模型提供的任何功能，包括默认排序、自定义管理器或自定义模型方法。</p>
<p>如果你希望存储与 <code class="docutils literal notranslate"><span class="pre">User</span></code> 相关的信息，你可以使用一个 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.OneToOneField" title="django.db.models.OneToOneField"><code class="xref py py-class docutils literal notranslate"><span class="pre">OneToOneField</span></code></a> 到一个包含字段的模型，以获得额外的信息。这种一对一的模型通常被称为 profile 模型，因为它可能会存储一个站点用户的非认证相关信息。例如，你可以创建一个 Employee 模型：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">User</span>

<span class="k">class</span> <span class="nc">Employee</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">user</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">OneToOneField</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">CASCADE</span><span class="p">)</span>
    <span class="n">department</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
</pre></div>
</div>
<p>假设现有的雇员 Fred Smith 同时拥有 User 和 Employee 模型，可以使用 Django 的标准关联模型约束来访问相关信息：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">u</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s1">&#39;fsmith&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">freds_department</span> <span class="o">=</span> <span class="n">u</span><span class="o">.</span><span class="n">employee</span><span class="o">.</span><span class="n">department</span>
</pre></div>
</div>
<p>要将配置文件模型的字段添加到管理员的用户页面中，在你的应用程序的 <code class="docutils literal notranslate"><span class="pre">admin.py</span></code> 中定义一个 <a class="reference internal" href="../../ref/contrib/admin/index.html#django.contrib.admin.InlineModelAdmin" title="django.contrib.admin.InlineModelAdmin"><code class="xref py py-class docutils literal notranslate"><span class="pre">InlineModelAdmin</span></code></a> （在这个例子中，我们将使用一个 <a class="reference internal" href="../../ref/contrib/admin/index.html#django.contrib.admin.StackedInline" title="django.contrib.admin.StackedInline"><code class="xref py py-class docutils literal notranslate"><span class="pre">StackedInline</span></code></a>），并将其添加到一个 <code class="docutils literal notranslate"><span class="pre">UserAdmin</span></code> 类中，该类用 <code class="xref py py-class docutils literal notranslate"><span class="pre">User`</span></code> 类注册：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.admin</span> <span class="kn">import</span> <span class="n">UserAdmin</span> <span class="k">as</span> <span class="n">BaseUserAdmin</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">User</span>

<span class="kn">from</span> <span class="nn">my_user_profile_app.models</span> <span class="kn">import</span> <span class="n">Employee</span>

<span class="c1"># Define an inline admin descriptor for Employee model</span>
<span class="c1"># which acts a bit like a singleton</span>
<span class="k">class</span> <span class="nc">EmployeeInline</span><span class="p">(</span><span class="n">admin</span><span class="o">.</span><span class="n">StackedInline</span><span class="p">):</span>
    <span class="n">model</span> <span class="o">=</span> <span class="n">Employee</span>
    <span class="n">can_delete</span> <span class="o">=</span> <span class="kc">False</span>
    <span class="n">verbose_name_plural</span> <span class="o">=</span> <span class="s1">&#39;employee&#39;</span>

<span class="c1"># Define a new User admin</span>
<span class="k">class</span> <span class="nc">UserAdmin</span><span class="p">(</span><span class="n">BaseUserAdmin</span><span class="p">):</span>
    <span class="n">inlines</span> <span class="o">=</span> <span class="p">(</span><span class="n">EmployeeInline</span><span class="p">,)</span>

<span class="c1"># Re-register UserAdmin</span>
<span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">unregister</span><span class="p">(</span><span class="n">User</span><span class="p">)</span>
<span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">UserAdmin</span><span class="p">)</span>
</pre></div>
</div>
<p>这些 profile 模型并没有任何特殊之处——它们只是 Django 模型，恰好与用户模型有一对一的联系。因此，当用户被创建时，它们并不会自动创建，但可以用一个 <a class="reference internal" href="../../ref/signals.html#django.db.models.signals.post_save" title="django.db.models.signals.post_save"><code class="xref py py-attr docutils literal notranslate"><span class="pre">django.db.models.signals.post_save</span></code></a> 来适当地创建或更新相关模型。</p>
<p>使用相关模型会导致额外的查询或连接来检索相关数据。根据你的需求，包含相关字段的自定义用户模型可能是你更好的选择，然而，在你的项目应用程序中与默认用户模型的现有关系可能会证明额外的数据库负载是合理的。</p>
</div>
<div class="section" id="s-substituting-a-custom-user-model">
<span id="s-auth-custom-user"></span><span id="substituting-a-custom-user-model"></span><span id="auth-custom-user"></span><h2>替换一个自定义的 <code class="docutils literal notranslate"><span class="pre">User</span></code> 模型。<a class="headerlink" href="#substituting-a-custom-user-model" title="永久链接至标题">¶</a></h2>
<p>有些项目可能会有认证需求，而 Django 内置的 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 模型并不总是合适。例如，在一些网站上，使用电子邮件地址作为你的身份识别标记比使用用户名更有意义。</p>
<p>Django 允许你通过为 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 配置提供一个引用自定义模型的值来覆盖默认的用户模型：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">AUTH_USER_MODEL</span> <span class="o">=</span> <span class="s1">&#39;myapp.MyUser&#39;</span>
</pre></div>
</div>
<p>这个引号对描述了 Django 应用的名称（必须在你的 <a class="reference internal" href="../../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 中），以及你希望作为用户模型的 Django 模型的名称。</p>
<div class="section" id="s-using-a-custom-user-model-when-starting-a-project">
<span id="using-a-custom-user-model-when-starting-a-project"></span><h3>启动项目时使用自定义用户模型<a class="headerlink" href="#using-a-custom-user-model-when-starting-a-project" title="永久链接至标题">¶</a></h3>
<p>如果你准备启动一个新的项目，强烈推荐你设置一个自定义的用户模型，即使默认的用户模型对你来说已经足够了。这个模型的行为与默认用户模型相通，但是你能在未来需要的时候自定义它：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">AbstractUser</span>

<span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">AbstractUser</span><span class="p">):</span>
    <span class="k">pass</span>
</pre></div>
</div>
<p>不要忘记将 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 指向它。在创建任何迁移或者首次运行 <code class="docutils literal notranslate"><span class="pre">manage.py</span> <span class="pre">migrate</span></code> 之前执行这个操作。</p>
<p>同样的，在 app 中的 <code class="docutils literal notranslate"><span class="pre">admin.py</span></code> 中注册模型。</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.admin</span> <span class="kn">import</span> <span class="n">UserAdmin</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">User</span>

<span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">UserAdmin</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-changing-to-a-custom-user-model-mid-project">
<span id="changing-to-a-custom-user-model-mid-project"></span><h3>在项目中更改为自定义用户模型。<a class="headerlink" href="#changing-to-a-custom-user-model-mid-project" title="永久链接至标题">¶</a></h3>
<p>在你已经建立数据库表之后再去修改 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 要困难的多，因为它会影响外键和多对多关系。</p>
<p>这个改动并不能自动完成，需要手动修复你的架构，将数据从旧的用户表移出，并有可能需要手动执行一些迁移操作。查看步骤概述，请查看 <a class="reference external" href="https://code.djangoproject.com/ticket/25313">#25313</a>。</p>
<p>由于 Django 对可交换模型的动态依赖特性的限制，<a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 所引用的模型必须在其应用的第一次迁移中创建（通常称为 <code class="docutils literal notranslate"><span class="pre">0001_initial</span></code>）；否则，你会出现依赖问题。</p>
<p>此外，当你运行迁移时，你可能会遇到一个 <code class="docutils literal notranslate"><span class="pre">CircularDependencyError</span></code>，因为 Django 不会因为动态依赖而自动打破依赖循环。如果你看到这个错误，你应该通过将你的用户模型所依赖的模型移动到第二个迁移中来打破这个循环。（如果你想看看通常是怎么做的，你可以尝试做两个正常的模型，它们之间有一个 <code class="docutils literal notranslate"><span class="pre">ForeignKey</span></code>，看看 <code class="docutils literal notranslate"><span class="pre">makemigrations</span></code> 是如何解决这个循环依赖的。）</p>
</div>
<div class="section" id="s-reusable-apps-and-auth-user-model">
<span id="reusable-apps-and-auth-user-model"></span><h3>可重用应用和 <code class="docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code><a class="headerlink" href="#reusable-apps-and-auth-user-model" title="永久链接至标题">¶</a></h3>
<p>可重用应用不应该实现自定义用户模型。一个项目可能会使用很多应用，两个实现了自定义用户模型的可重用应用不能一起使用。如果你需要在你的应用中存储每个用户的信息，可以使用一个 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 或 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.OneToOneField" title="django.db.models.OneToOneField"><code class="xref py py-class docutils literal notranslate"><span class="pre">OneToOneField</span></code></a> 到 <cite>settings.AUTH_USER_MODEL</cite>，如下所述。</p>
</div>
<div class="section" id="s-referencing-the-user-model">
<span id="referencing-the-user-model"></span><h3>引用 <code class="docutils literal notranslate"><span class="pre">User</span></code> 模型<a class="headerlink" href="#referencing-the-user-model" title="永久链接至标题">¶</a></h3>
<p>如果你直接引用 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> （例如，通过在一个外键中引用它），你的代码将无法在 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 配置已被更改为不同用户模型的项目中工作。</p>
<dl class="function">
<dt id="django.contrib.auth.get_user_model">
<code class="descname">get_user_model</code>()<a class="headerlink" href="#django.contrib.auth.get_user_model" title="永久链接至目标">¶</a></dt>
<dd><p>与其直接引用 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a>，不如使用 <code class="docutils literal notranslate"><span class="pre">django.contrib.auth.get_user_model()</span></code> 引用用户模型。这个方法将返回当前活动的用户模型——如果指定了自定义用户模型，则返回自定义用户模型，否则返回 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a>。</p>
<p>在定义用户模型的外键或多对多关系时，应使用 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 配置指定自定义模型。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">Article</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">author</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span>
        <span class="n">settings</span><span class="o">.</span><span class="n">AUTH_USER_MODEL</span><span class="p">,</span>
        <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">CASCADE</span><span class="p">,</span>
    <span class="p">)</span>
</pre></div>
</div>
<p>连接用户模型发送的信号时，应使用 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 配置指定自定义模型。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.db.models.signals</span> <span class="kn">import</span> <span class="n">post_save</span>

<span class="k">def</span> <span class="nf">post_save_receiver</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">created</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="n">post_save</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">post_save_receiver</span><span class="p">,</span> <span class="n">sender</span><span class="o">=</span><span class="n">settings</span><span class="o">.</span><span class="n">AUTH_USER_MODEL</span><span class="p">)</span>
</pre></div>
</div>
<p>一般来说，在导入时执行的代码中，用 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 配置来引用用户模型是最简单的，不过，也可以在 Django 导入模型时调用 <code class="docutils literal notranslate"><span class="pre">get_user_model()</span></code>，所以可以使用 <code class="docutils literal notranslate"><span class="pre">models.ForeignKey(get_user_model()，...)</span></code>。</p>
<p>例如，如果你的应用是用多个用户模型进行测试的，使用 <code class="docutils literal notranslate"><span class="pre">&#64;override_settings(AUTH_USER_MODEL=...)</span></code>，并且你把 <code class="docutils literal notranslate"><span class="pre">get_user_model()</span></code> 的结果缓存在模块级变量中，你可能需要监听 <a class="reference internal" href="../../ref/signals.html#django.test.signals.setting_changed" title="django.test.signals.setting_changed"><code class="xref py py-data docutils literal notranslate"><span class="pre">setting_changed</span></code></a> 信号来清除缓存。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.apps</span> <span class="kn">import</span> <span class="n">apps</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth</span> <span class="kn">import</span> <span class="n">get_user_model</span>
<span class="kn">from</span> <span class="nn">django.core.signals</span> <span class="kn">import</span> <span class="n">setting_changed</span>
<span class="kn">from</span> <span class="nn">django.dispatch</span> <span class="kn">import</span> <span class="n">receiver</span>

<span class="nd">@receiver</span><span class="p">(</span><span class="n">setting_changed</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">user_model_swapped</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">kwargs</span><span class="p">[</span><span class="s1">&#39;setting&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;AUTH_USER_MODEL&#39;</span><span class="p">:</span>
        <span class="n">apps</span><span class="o">.</span><span class="n">clear_cache</span><span class="p">()</span>
        <span class="kn">from</span> <span class="nn">myapp</span> <span class="kn">import</span> <span class="n">some_module</span>
        <span class="n">some_module</span><span class="o">.</span><span class="n">UserModel</span> <span class="o">=</span> <span class="n">get_user_model</span><span class="p">()</span>
</pre></div>
</div>
</dd></dl>

</div>
<div class="section" id="s-specifying-a-custom-user-model">
<span id="s-specifying-custom-user-model"></span><span id="specifying-a-custom-user-model"></span><span id="specifying-custom-user-model"></span><h3>指定自定义用户模型<a class="headerlink" href="#specifying-a-custom-user-model" title="永久链接至标题">¶</a></h3>
<p>当你用自定义用户模型开始你的项目时，请停下来考虑一下这是否是你项目的正确选择。</p>
<p>将所有用户相关信息保存在一个模型中，就不需要额外的或更复杂的数据库查询来检索相关模型。另一方面，在一个与你的自定义用户模型有关系的模型中存储特定应用的用户信息可能更合适。这允许每个应用程序指定自己的用户数据需求，而不会有潜在的冲突或破坏其他应用程序的假设。这也意味着，你会让你的用户模型尽可能的简单，专注于认证，并遵循 Django 期望自定义用户模型满足的最低要求。</p>
<p>如果你使用默认的认证后端，那么你的模型必须有一个可用于识别目的的唯一字段。这可以是一个用户名，一个电子邮件地址，或任何其他独特的属性。如果你使用可以支持的自定义认证后端，则允许使用非唯一的用户名字段。</p>
<p>最简单的方法是继承 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a>。 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a> 提供了用户模型的核心实现，包括哈希密码和令牌化密码重置。然后你必须提供一些关键的实现细节。</p>
<dl class="class">
<dt id="django.contrib.auth.models.CustomUser">
<em class="property">class </em><code class="descclassname">models.</code><code class="descname">CustomUser</code><a class="headerlink" href="#django.contrib.auth.models.CustomUser" title="永久链接至目标">¶</a></dt>
<dd><dl class="attribute">
<dt id="django.contrib.auth.models.CustomUser.USERNAME_FIELD">
<code class="descname">USERNAME_FIELD</code><a class="headerlink" href="#django.contrib.auth.models.CustomUser.USERNAME_FIELD" title="永久链接至目标">¶</a></dt>
<dd><p>描述用户模型上用作唯一标识符的字段名称的字符串。这通常是某种用户名，但也可以是电子邮件地址，或任何其他独特的标识符。该字段 <em>必须</em> 是唯一的（即在其定义中设置了 <code class="docutils literal notranslate"><span class="pre">unique=True</span></code>），除非你使用的自定义认证后端可以支持非唯一的用户名。</p>
<p>接下来的样例中，<code class="docutils literal notranslate"><span class="pre">identifier</span></code> 字段将被用作识别字段：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyUser</span><span class="p">(</span><span class="n">AbstractBaseUser</span><span class="p">):</span>
    <span class="n">identifier</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">40</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
    <span class="o">...</span>
    <span class="n">USERNAME_FIELD</span> <span class="o">=</span> <span class="s1">&#39;identifier&#39;</span>
</pre></div>
</div>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.auth.models.CustomUser.EMAIL_FIELD">
<code class="descname">EMAIL_FIELD</code><a class="headerlink" href="#django.contrib.auth.models.CustomUser.EMAIL_FIELD" title="永久链接至目标">¶</a></dt>
<dd><p>用来描述用户模型中的邮件字段，该值通过 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser.get_email_field_name" title="django.contrib.auth.models.AbstractBaseUser.get_email_field_name"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_email_field_name()</span></code></a> 返回。</p>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.auth.models.CustomUser.REQUIRED_FIELDS">
<code class="descname">REQUIRED_FIELDS</code><a class="headerlink" href="#django.contrib.auth.models.CustomUser.REQUIRED_FIELDS" title="永久链接至目标">¶</a></dt>
<dd><p>在通过 <a class="reference internal" href="../../ref/django-admin.html#django-admin-createsuperuser"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">createsuperuser</span></code></a> 管理命令创建用户时，将提示用户输入的字段名称列表。用户将被提示为每个字段提供一个值。它必须包括 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.Field.blank" title="django.db.models.Field.blank"><code class="xref py py-attr docutils literal notranslate"><span class="pre">blank</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 或未定义的任何字段，并可能包括你希望在交互式创建用户时提示的其他字段。<code class="docutils literal notranslate"><span class="pre">REQUIRED_FIELDS</span></code> 在 Django 的其他部分没有效果，比如在管理中创建用户。</p>
<p>例如，这里是一个用户模型的部分定义，它定义了两个必填字段——出生日期和身高：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyUser</span><span class="p">(</span><span class="n">AbstractBaseUser</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">date_of_birth</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">()</span>
    <span class="n">height</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">FloatField</span><span class="p">()</span>
    <span class="o">...</span>
    <span class="n">REQUIRED_FIELDS</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;date_of_birth&#39;</span><span class="p">,</span> <span class="s1">&#39;height&#39;</span><span class="p">]</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last"><code class="docutils literal notranslate"><span class="pre">REQUIRED_FIELDS</span></code> 必须包含用户模型上的所有必填字段，但 <em>不应</em> 包含 <code class="docutils literal notranslate"><span class="pre">USERNAME_FIELD</span></code> 或 <code class="docutils literal notranslate"><span class="pre">password</span></code>，因为这些字段总是会被提示。</p>
</div>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.auth.models.CustomUser.is_active">
<code class="descname">is_active</code><a class="headerlink" href="#django.contrib.auth.models.CustomUser.is_active" title="永久链接至目标">¶</a></dt>
<dd><p>一个布尔属性，表示用户是否被认为是 “激活的”。 这个属性作为 <code class="docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code> 的属性，默认为 <code class="docutils literal notranslate"><span class="pre">True</span></code>。你如何选择实现它将取决于你所选择的认证后端的细节。详情请参考内置用户模型的 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_active" title="django.contrib.auth.models.User.is_active"><code class="xref py py-attr docutils literal notranslate"><span class="pre">is_active</span> <span class="pre">属性的文档</span></code></a>。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.CustomUser.get_full_name">
<code class="descname">get_full_name</code>()<a class="headerlink" href="#django.contrib.auth.models.CustomUser.get_full_name" title="永久链接至目标">¶</a></dt>
<dd><p>可选项。用户的较长身份标识符，比如用户的全名。如果已经设置，则会与用户名一起出现在 <a class="reference internal" href="../../ref/contrib/admin/index.html#module-django.contrib.admin" title="django.contrib.admin: Django's admin site."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.admin</span></code></a> 中。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.CustomUser.get_short_name">
<code class="descname">get_short_name</code>()<a class="headerlink" href="#django.contrib.auth.models.CustomUser.get_short_name" title="永久链接至目标">¶</a></dt>
<dd><p>可选项。用户较短的身份标识符，比如用户的名。如果已经设置，它会在 <a class="reference internal" href="../../ref/contrib/admin/index.html#module-django.contrib.admin" title="django.contrib.admin: Django's admin site."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.admin</span></code></a> 页面头部的欢迎词中替换用户名。</p>
</dd></dl>

<div class="admonition-importing-abstractbaseuser admonition">
<p class="first admonition-title">导入 <code class="docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></p>
<p class="last"><code class="docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code> and <code class="docutils literal notranslate"><span class="pre">BaseUserManager</span></code> 可以从 <code class="docutils literal notranslate"><span class="pre">django.contrib.auth.base_user</span></code> 中导入，所以你无需在 <a class="reference internal" href="../../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 添加 <code class="docutils literal notranslate"><span class="pre">django.contrib.auth</span></code>&nbsp;就能导入它们。</p>
</div>
</dd></dl>

<p><a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a> 的任何子类都可以使用下面的属性和方法：</p>
<dl class="class">
<dt id="django.contrib.auth.models.AbstractBaseUser">
<em class="property">class </em><code class="descclassname">models.</code><code class="descname">AbstractBaseUser</code><a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser" title="永久链接至目标">¶</a></dt>
<dd><dl class="method">
<dt id="django.contrib.auth.models.AbstractBaseUser.get_username">
<code class="descname">get_username</code>()<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.get_username" title="永久链接至目标">¶</a></dt>
<dd><p>返回 <code class="docutils literal notranslate"><span class="pre">USERNAME_FIELD</span></code> 指定的字段的值。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.AbstractBaseUser.clean">
<code class="descname">clean</code>()<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.clean" title="永久链接至目标">¶</a></dt>
<dd><p>通过调用 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser.normalize_username" title="django.contrib.auth.models.AbstractBaseUser.normalize_username"><code class="xref py py-meth docutils literal notranslate"><span class="pre">normalize_username()</span></code></a> 来规范化用户名。 如果重写此方法，必须调用 <code class="docutils literal notranslate"><span class="pre">super()</span></code> 来保持规范化。</p>
</dd></dl>

<dl class="classmethod">
<dt id="django.contrib.auth.models.AbstractBaseUser.get_email_field_name">
<em class="property">classmethod </em><code class="descname">get_email_field_name</code>()<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.get_email_field_name" title="永久链接至目标">¶</a></dt>
<dd><p>返回由 <a class="reference internal" href="#django.contrib.auth.models.CustomUser.EMAIL_FIELD" title="django.contrib.auth.models.CustomUser.EMAIL_FIELD"><code class="xref py py-attr docutils literal notranslate"><span class="pre">EMAIL_FIELD</span></code></a> 属性指定的电子邮件字段的名称。 如果未指定 <code class="docutils literal notranslate"><span class="pre">EMAIL_FIELD</span></code> ，则默认为 <code class="docutils literal notranslate"><span class="pre">'email'</span></code> 。</p>
</dd></dl>

<dl class="classmethod">
<dt id="django.contrib.auth.models.AbstractBaseUser.normalize_username">
<em class="property">classmethod </em><code class="descname">normalize_username</code>(<em>username</em>)<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.normalize_username" title="永久链接至目标">¶</a></dt>
<dd><p>应用 NFKC Unicode 规范化用户名，使得不同 Unicode 码位视觉相同字符视为相同。</p>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.auth.models.AbstractBaseUser.is_authenticated">
<code class="descname">is_authenticated</code><a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.is_authenticated" title="永久链接至目标">¶</a></dt>
<dd><p>只读属性，始终返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> （匿名用户 <code class="docutils literal notranslate"><span class="pre">AnonymousUser.is_authenticated</span></code>  始终返回 <code class="docutils literal notranslate"><span class="pre">False</span></code> ）。这是一种判断用户是否已通过身份验证的方法。这并不意味着任何权限，也不会检查用户是否处于活动状态或是否具有有效会话。即使通常您会根据 <code class="docutils literal notranslate"><span class="pre">request.user</span></code> 检查这个属性，以确定它是否被 <a class="reference internal" href="../../ref/middleware.html#django.contrib.auth.middleware.AuthenticationMiddleware" title="django.contrib.auth.middleware.AuthenticationMiddleware"><code class="xref py py-class docutils literal notranslate"><span class="pre">AuthenticationMiddleware</span></code></a> 填充（表示当前登录的用户），但是你应该知道该属性对于任何 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 实例都返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>。</p>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.auth.models.AbstractBaseUser.is_anonymous">
<code class="descname">is_anonymous</code><a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.is_anonymous" title="永久链接至目标">¶</a></dt>
<dd><p>只读属性总是 <code class="docutils literal notranslate"><span class="pre">False</span></code>。这个属性用于区分 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 和 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.AnonymousUser" title="django.contrib.auth.models.AnonymousUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AnonymousUser</span></code></a> 对象。通常情况下， <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_authenticated" title="django.contrib.auth.models.User.is_authenticated"><code class="xref py py-attr docutils literal notranslate"><span class="pre">is_authenticated</span></code></a> 应该置于只读。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.AbstractBaseUser.set_password">
<code class="descname">set_password</code>(<em>raw_password</em>)<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.set_password" title="永久链接至目标">¶</a></dt>
<dd><p>设置用户密码，谨慎保存密码哈希。不可保存 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a> 的对象。</p>
<p>当 raw_password 为 <code class="docutils literal notranslate"><span class="pre">None</span></code> 时，密码将被设置为不可用的密码，就像 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser.set_unusable_password" title="django.contrib.auth.models.AbstractBaseUser.set_unusable_password"><code class="xref py py-meth docutils literal notranslate"><span class="pre">set_unusable_password()</span></code></a> 一样。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.AbstractBaseUser.check_password">
<code class="descname">check_password</code>(<em>raw_password</em>)<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.check_password" title="永久链接至目标">¶</a></dt>
<dd><p>如果给定的原始字符串是用户的正确密码，返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>。（在进行比较时，这将处理密码散列。）</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.AbstractBaseUser.set_unusable_password">
<code class="descname">set_unusable_password</code>()<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.set_unusable_password" title="永久链接至目标">¶</a></dt>
<dd><p>将该用户标记为没有设置密码。 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser.check_password" title="django.contrib.auth.models.AbstractBaseUser.check_password"><code class="xref py py-meth docutils literal notranslate"><span class="pre">check_password()</span></code></a> 对这个用户的检查永远不会返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>。不保存 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a> 对象。</p>
<p>如果你的应用程序的身份验证是针对现有的外部源（如 LDAP 目录）进行的，你可能需要这个功能。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.AbstractBaseUser.has_usable_password">
<code class="descname">has_usable_password</code>()<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.has_usable_password" title="永久链接至目标">¶</a></dt>
<dd><p>如果 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser.set_unusable_password" title="django.contrib.auth.models.AbstractBaseUser.set_unusable_password"><code class="xref py py-meth docutils literal notranslate"><span class="pre">set_unusable_password()</span></code></a> 被调用，返回 <code class="docutils literal notranslate"><span class="pre">False</span></code>。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash">
<code class="descname">get_session_auth_hash</code>()<a class="headerlink" href="#django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash" title="永久链接至目标">¶</a></dt>
<dd><p>返回密码字段的 HMAC。用于 <span class="xref std std-ref">session-invalidation-onpassword-change</span>。</p>
<div class="versionchanged">
<span class="title">Changed in Django 3.1:</span> <p>哈希算法已更改为 SHA-256。</p>
</div>
</dd></dl>

</dd></dl>

<p><a class="reference internal" href="#django.contrib.auth.models.AbstractUser" title="django.contrib.auth.models.AbstractUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractUser</span></code></a> 是 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a> 的子类。</p>
<dl class="class">
<dt id="django.contrib.auth.models.AbstractUser">
<em class="property">class </em><code class="descclassname">models.</code><code class="descname">AbstractUser</code><a class="headerlink" href="#django.contrib.auth.models.AbstractUser" title="永久链接至目标">¶</a></dt>
<dd><dl class="method">
<dt id="django.contrib.auth.models.AbstractUser.clean">
<code class="descname">clean</code>()<a class="headerlink" href="#django.contrib.auth.models.AbstractUser.clean" title="永久链接至目标">¶</a></dt>
<dd><p>通过调用 <a class="reference internal" href="#django.contrib.auth.models.BaseUserManager.normalize_email" title="django.contrib.auth.models.BaseUserManager.normalize_email"><code class="xref py py-meth docutils literal notranslate"><span class="pre">BaseUserManager.normalize_email()</span></code></a> 来规范化邮件。如果你覆盖了这个方法，一定要调用 <code class="docutils literal notranslate"><span class="pre">super()</span></code> 来保留规范化。</p>
</dd></dl>

</dd></dl>

</div>
<div class="section" id="s-writing-a-manager-for-a-custom-user-model">
<span id="writing-a-manager-for-a-custom-user-model"></span><h3>为自定义的用户模型编写一个管理器<a class="headerlink" href="#writing-a-manager-for-a-custom-user-model" title="永久链接至标题">¶</a></h3>
<p>你也该为你的用户模型定义一个自定义管理器。如果你的用户模型定义了和默认用户相同的 <code class="docutils literal notranslate"><span class="pre">username</span></code>, <code class="docutils literal notranslate"><span class="pre">email</span></code>, <code class="docutils literal notranslate"><span class="pre">is_staff</span></code>, <code class="docutils literal notranslate"><span class="pre">is_active</span></code>, <code class="docutils literal notranslate"><span class="pre">is_superuser</span></code>, <code class="docutils literal notranslate"><span class="pre">last_login</span></code>, 和 <a href="#id1"><span class="problematic" id="id2">``</span></a>date_joined`等字段，你可以安装 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.UserManager" title="django.contrib.auth.models.UserManager"><code class="xref py py-class docutils literal notranslate"><span class="pre">UserManager</span></code></a> ；但是，如果你的用户模型还定义了其他字段，那么就需要定义一个自定义管理器，它扩展了 <a class="reference internal" href="#django.contrib.auth.models.BaseUserManager" title="django.contrib.auth.models.BaseUserManager"><code class="xref py py-class docutils literal notranslate"><span class="pre">BaseUserManager</span></code></a> ，提供了两个额外的方法：</p>
<dl class="class">
<dt id="django.contrib.auth.models.CustomUserManager">
<em class="property">class </em><code class="descclassname">models.</code><code class="descname">CustomUserManager</code><a class="headerlink" href="#django.contrib.auth.models.CustomUserManager" title="永久链接至目标">¶</a></dt>
<dd><dl class="method">
<dt id="django.contrib.auth.models.CustomUserManager.create_user">
<code class="descname">create_user</code>(<em>username_field</em>, <em>password=None</em>, <em>**other_fields</em>)<a class="headerlink" href="#django.contrib.auth.models.CustomUserManager.create_user" title="永久链接至目标">¶</a></dt>
<dd><p><code class="docutils literal notranslate"><span class="pre">create_user()</span></code> 的原型应该接受username字段，加上其他所有必须的字段作为参数。举例，如果你的用户模型使用 <code class="docutils literal notranslate"><span class="pre">email</span></code> 作为用户名字段，<code class="docutils literal notranslate"><span class="pre">date_of_birth</span></code>&nbsp; 字段作为必填字段，那么 <code class="docutils literal notranslate"><span class="pre">create_user</span></code> 应该如下定义：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">create_user</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">date_of_birth</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
    <span class="c1"># create user here</span>
    <span class="o">...</span>
</pre></div>
</div>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.CustomUserManager.create_superuser">
<code class="descname">create_superuser</code>(<em>username_field</em>, <em>password=None</em>, <em>**other_fields</em>)<a class="headerlink" href="#django.contrib.auth.models.CustomUserManager.create_superuser" title="永久链接至目标">¶</a></dt>
<dd><p><code class="docutils literal notranslate"><span class="pre">create_superuser()</span></code> 的原型应该接受username字段，加上其他所有必须的字段作为参数。举例，如果你的用户模型使用 <code class="docutils literal notranslate"><span class="pre">email</span></code> 作为用户名字段，<code class="docutils literal notranslate"><span class="pre">date_of_birth</span></code> 字段作为必填字段，那么 <code class="docutils literal notranslate"><span class="pre">create_superuser</span></code> 应该如下定义：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">create_superuser</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">date_of_birth</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
    <span class="c1"># create superuser here</span>
    <span class="o">...</span>
</pre></div>
</div>
</dd></dl>

</dd></dl>

<p>对于 <a class="reference internal" href="#django.contrib.auth.models.CustomUser.USERNAME_FIELD" title="django.contrib.auth.models.CustomUser.USERNAME_FIELD"><code class="xref py py-attr docutils literal notranslate"><span class="pre">USERNAME_FIELD</span></code></a> 或 <a class="reference internal" href="#django.contrib.auth.models.CustomUser.REQUIRED_FIELDS" title="django.contrib.auth.models.CustomUser.REQUIRED_FIELDS"><code class="xref py py-attr docutils literal notranslate"><span class="pre">REQUIRED_FIELDS</span></code></a> 中的 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> ，这些方法接收现有实例的:attr:<cite>~.ForeignKey.to_field</cite> （默认为 <a class="reference internal" href="../../ref/models/fields.html#django.db.models.Field.primary_key" title="django.db.models.Field.primary_key"><code class="xref py py-attr docutils literal notranslate"><span class="pre">primary_key</span></code></a> ）的值。</p>
<p><a class="reference internal" href="#django.contrib.auth.models.BaseUserManager" title="django.contrib.auth.models.BaseUserManager"><code class="xref py py-class docutils literal notranslate"><span class="pre">BaseUserManager</span></code></a> 提供以下实用方法：</p>
<dl class="class">
<dt id="django.contrib.auth.models.BaseUserManager">
<em class="property">class </em><code class="descclassname">models.</code><code class="descname">BaseUserManager</code><a class="headerlink" href="#django.contrib.auth.models.BaseUserManager" title="永久链接至目标">¶</a></dt>
<dd><dl class="classmethod">
<dt id="django.contrib.auth.models.BaseUserManager.normalize_email">
<em class="property">classmethod </em><code class="descname">normalize_email</code>(<em>email</em>)<a class="headerlink" href="#django.contrib.auth.models.BaseUserManager.normalize_email" title="永久链接至目标">¶</a></dt>
<dd><p>通过降低电子邮件地址的域部分来规范化电子邮件地址。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.BaseUserManager.get_by_natural_key">
<code class="descname">get_by_natural_key</code>(<em>username</em>)<a class="headerlink" href="#django.contrib.auth.models.BaseUserManager.get_by_natural_key" title="永久链接至目标">¶</a></dt>
<dd><p>使用 <code class="docutils literal notranslate"><span class="pre">USERNAME_FIELD</span></code> 指定的字段的内容检索用户实例。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.BaseUserManager.make_random_password">
<code class="descname">make_random_password</code>(<em>length=10</em>, <em>allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'</em>)<a class="headerlink" href="#django.contrib.auth.models.BaseUserManager.make_random_password" title="永久链接至目标">¶</a></dt>
<dd><p>返回具有给定长度和给定字符串的随机密码。请注意， <code class="docutils literal notranslate"><span class="pre">allowed_chars</span></code>  的默认值不包含可能导致用户混淆的字母，包括：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">i</span></code>, <code class="docutils literal notranslate"><span class="pre">l</span></code>, <code class="docutils literal notranslate"><span class="pre">I</span></code>, 和 <code class="docutils literal notranslate"><span class="pre">1</span></code> (小写i, 小写L, 大写i和数字1)</li>
<li><code class="docutils literal notranslate"><span class="pre">o</span></code>, <code class="docutils literal notranslate"><span class="pre">O</span></code>, 和 <code class="docutils literal notranslate"><span class="pre">0</span></code> (小写 o, 大写 o, 和数字0 )</li>
</ul>
</dd></dl>

</dd></dl>

</div>
<div class="section" id="s-extending-django-s-default-user">
<span id="extending-django-s-default-user"></span><h3>扩展Django的默认用户模型<a class="headerlink" href="#extending-django-s-default-user" title="永久链接至标题">¶</a></h3>
<p>如果你对Django自带的用户模型完全满意，而你又想添加一些其他信息，你可以继承 <a class="reference internal" href="#django.contrib.auth.models.AbstractUser" title="django.contrib.auth.models.AbstractUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">django.contrib.auth.models.AbstractUser</span></code></a>  并添加你的自定义字段，不过我们建议使用在“模型设计考虑因素”中描述 <a class="reference internal" href="#specifying-custom-user-model"><span class="std std-ref">指定自定义用户模型</span></a> 那样的单独的模型。  <code class="docutils literal notranslate"><span class="pre">AbstractUser</span></code> 提供默认 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 的完整实现作为 :ref:<a href="#id1"><span class="problematic" id="id2">`</span></a>abstract model ` 。</p>
</div>
<div class="section" id="s-custom-users-and-the-built-in-auth-forms">
<span id="s-id2"></span><span id="custom-users-and-the-built-in-auth-forms"></span><span id="id2"></span><h3>自定义用户和内建的auth表单<a class="headerlink" href="#custom-users-and-the-built-in-auth-forms" title="永久链接至标题">¶</a></h3>
<p>Django的内置 :ref:<a href="#id1"><span class="problematic" id="id2">`</span></a>forms ` 和 :ref:<a href="#id3"><span class="problematic" id="id4">`</span></a>views ` 对他们正在使用的用户模型做了一些假设。</p>
<p>以下表单与 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a> 的任何子类兼容：</p>
<ul class="simple">
<li><a class="reference internal" href="default.html#django.contrib.auth.forms.AuthenticationForm" title="django.contrib.auth.forms.AuthenticationForm"><code class="xref py py-class docutils literal notranslate"><span class="pre">AuthenticationForm</span></code></a>:  使用 <a class="reference internal" href="#django.contrib.auth.models.CustomUser.USERNAME_FIELD" title="django.contrib.auth.models.CustomUser.USERNAME_FIELD"><code class="xref py py-attr docutils literal notranslate"><span class="pre">USERNAME_FIELD</span></code></a> 指定的username字段。</li>
<li><a class="reference internal" href="default.html#django.contrib.auth.forms.SetPasswordForm" title="django.contrib.auth.forms.SetPasswordForm"><code class="xref py py-class docutils literal notranslate"><span class="pre">SetPasswordForm</span></code></a></li>
<li><a class="reference internal" href="default.html#django.contrib.auth.forms.PasswordChangeForm" title="django.contrib.auth.forms.PasswordChangeForm"><code class="xref py py-class docutils literal notranslate"><span class="pre">PasswordChangeForm</span></code></a></li>
<li><a class="reference internal" href="default.html#django.contrib.auth.forms.AdminPasswordChangeForm" title="django.contrib.auth.forms.AdminPasswordChangeForm"><code class="xref py py-class docutils literal notranslate"><span class="pre">AdminPasswordChangeForm</span></code></a></li>
</ul>
<p>以下表单对用户模型进行了假设，如果满足这些假设，则可以按原样使用:</p>
<ul class="simple">
<li><a class="reference internal" href="default.html#django.contrib.auth.forms.PasswordResetForm" title="django.contrib.auth.forms.PasswordResetForm"><code class="xref py py-class docutils literal notranslate"><span class="pre">PasswordResetForm</span></code></a> ：假设用户模型有一个字段存储用户的电子邮件地址，其名称由 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser.get_email_field_name" title="django.contrib.auth.models.AbstractBaseUser.get_email_field_name"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_email_field_name()</span></code></a> 返回（默认为电子邮件），这个方法用来标识用户，以及名为``is_active``的布尔字段，防止非活动用户重置密码。</li>
</ul>
<p>最后，下面的表单和 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 绑定，如果需要和自定义的用户模型一起使用，则需要重写或者扩展。</p>
<ul class="simple">
<li><a class="reference internal" href="default.html#django.contrib.auth.forms.UserCreationForm" title="django.contrib.auth.forms.UserCreationForm"><code class="xref py py-class docutils literal notranslate"><span class="pre">UserCreationForm</span></code></a></li>
<li><a class="reference internal" href="default.html#django.contrib.auth.forms.UserChangeForm" title="django.contrib.auth.forms.UserChangeForm"><code class="xref py py-class docutils literal notranslate"><span class="pre">UserChangeForm</span></code></a></li>
</ul>
<p>如果自定义的用户模型是 <code class="docutils literal notranslate"><span class="pre">AbstractUser</span></code> 的子类，则可以使用下面的方式来扩展表单：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.auth.forms</span> <span class="kn">import</span> <span class="n">UserCreationForm</span>
<span class="kn">from</span> <span class="nn">myapp.models</span> <span class="kn">import</span> <span class="n">CustomUser</span>

<span class="k">class</span> <span class="nc">CustomUserCreationForm</span><span class="p">(</span><span class="n">UserCreationForm</span><span class="p">):</span>

    <span class="k">class</span> <span class="nc">Meta</span><span class="p">(</span><span class="n">UserCreationForm</span><span class="o">.</span><span class="n">Meta</span><span class="p">):</span>
        <span class="n">model</span> <span class="o">=</span> <span class="n">CustomUser</span>
        <span class="n">fields</span> <span class="o">=</span> <span class="n">UserCreationForm</span><span class="o">.</span><span class="n">Meta</span><span class="o">.</span><span class="n">fields</span> <span class="o">+</span> <span class="p">(</span><span class="s1">&#39;custom_field&#39;</span><span class="p">,)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-custom-users-and-django-contrib-admin">
<span id="custom-users-and-django-contrib-admin"></span><h3>自定义用户和 <a class="reference internal" href="../../ref/contrib/admin/index.html#module-django.contrib.admin" title="django.contrib.admin: Django's admin site."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.admin</span></code></a><a class="headerlink" href="#custom-users-and-django-contrib-admin" title="永久链接至标题">¶</a></h3>
<p>如果你希望自定义的用户模型也与管理后台一起使用，那么你的用户模型必须定义一些额外的属性和方法。这些方法允许管理员控制用户对管理后台内容的访问：</p>
<dl class="class">
<dt>
<em class="property">class </em><code class="descclassname">models.</code><code class="descname">CustomUser</code></dt>
<dd></dd></dl>

<dl class="attribute">
<dt id="django.contrib.auth.is_staff">
<code class="descname">is_staff</code><a class="headerlink" href="#django.contrib.auth.is_staff" title="永久链接至目标">¶</a></dt>
<dd><p>如果允许用户有访问 admin 页面就返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>。</p>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.auth.is_active">
<code class="descname">is_active</code><a class="headerlink" href="#django.contrib.auth.is_active" title="永久链接至目标">¶</a></dt>
<dd><p>返回``True``，如果该用户的账号当前是激活状态</p>
</dd></dl>

<dl class="method">
<dt>
<code class="descname">has_perm(perm, obj=None):</code></dt>
<dd><p>如果用户有指定的权限，则返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>&nbsp;。如果提供了参数 <code class="docutils literal notranslate"><span class="pre">obj</span></code>&nbsp; ，则需要对指定的对象实例进行权限检查。</p>
</dd></dl>

<dl class="method">
<dt>
<code class="descname">has_module_perms(app_label):</code></dt>
<dd><p>如果用户有权限访问指定 app 里的模型，那么返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>&nbsp;。</p>
</dd></dl>

<p>你也需要在 admin 文件里注册自定义的用户模型。如果自定义的用户模型扩展了  <code class="docutils literal notranslate"><span class="pre">django.contrib.auth.models.AbstractUser</span></code> ，你可以直接使用Django已有的类 <code class="docutils literal notranslate"><span class="pre">django.contrib.auth.admin.UserAdmin</span></code> 。如果你的用户模型扩展了 <a class="reference internal" href="#django.contrib.auth.models.AbstractBaseUser" title="django.contrib.auth.models.AbstractBaseUser"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseUser</span></code></a> ，你将需要定义一个自定义的类 <code class="docutils literal notranslate"><span class="pre">ModelAdmin</span></code>&nbsp;。不管怎样，你都将需要重写任何引用 <code class="docutils literal notranslate"><span class="pre">django.contrib.auth.models.AbstractUser</span></code> 上的字段的定义，这些字段不在你自定义的用户类中。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p>如果正在使用自定义的 <code class="docutils literal notranslate"><span class="pre">ModelAdmin</span></code> 是 <code class="docutils literal notranslate"><span class="pre">django.contrib.auth.admin.UserAdmin</span></code> 的子类，那么你需要添加自定义字段到 <code class="docutils literal notranslate"><span class="pre">fieldsets</span></code> （用于在编辑用户中使用）和 <code class="docutils literal notranslate"><span class="pre">add_fieldsets</span></code> （用于在创建用户时使用）。比如</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.auth.admin</span> <span class="kn">import</span> <span class="n">UserAdmin</span>

<span class="k">class</span> <span class="nc">CustomUserAdmin</span><span class="p">(</span><span class="n">UserAdmin</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">fieldsets</span> <span class="o">=</span> <span class="n">UserAdmin</span><span class="o">.</span><span class="n">fieldsets</span> <span class="o">+</span> <span class="p">(</span>
        <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;custom_field&#39;</span><span class="p">,)}),</span>
    <span class="p">)</span>
    <span class="n">add_fieldsets</span> <span class="o">=</span> <span class="n">UserAdmin</span><span class="o">.</span><span class="n">add_fieldsets</span> <span class="o">+</span> <span class="p">(</span>
        <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;custom_field&#39;</span><span class="p">,)}),</span>
    <span class="p">)</span>
</pre></div>
</div>
<p class="last">查看 <a class="reference internal" href="#custom-users-admin-full-example"><span class="std std-ref">a full example</span></a> 来了解更多细节。</p>
</div>
</div>
<div class="section" id="s-custom-users-and-permissions">
<span id="custom-users-and-permissions"></span><h3>自定义用户和权限。<a class="headerlink" href="#custom-users-and-permissions" title="永久链接至标题">¶</a></h3>
<p>为了便于将Django的权限框架引入到你自己的用户类中，Django提供了 <a class="reference internal" href="#django.contrib.auth.models.PermissionsMixin" title="django.contrib.auth.models.PermissionsMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">PermissionsMixin</span></code></a> 。这是一个抽象模型，可以包含在用户模型的类层次结构中，为你提供支持Django权限模型所需的所有方法和数据库字段。</p>
<p><a class="reference internal" href="#django.contrib.auth.models.PermissionsMixin" title="django.contrib.auth.models.PermissionsMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">PermissionsMixin</span></code></a> 提供下列方法和属性：</p>
<dl class="class">
<dt id="django.contrib.auth.models.PermissionsMixin">
<em class="property">class </em><code class="descclassname">models.</code><code class="descname">PermissionsMixin</code><a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin" title="永久链接至目标">¶</a></dt>
<dd><dl class="attribute">
<dt id="django.contrib.auth.models.PermissionsMixin.is_superuser">
<code class="descname">is_superuser</code><a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin.is_superuser" title="永久链接至目标">¶</a></dt>
<dd><p>布尔值。指定该用户拥有所有权限，而不用一个个开启权限。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.PermissionsMixin.get_user_permissions">
<code class="descname">get_user_permissions</code>(<em>obj=None</em>)<a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin.get_user_permissions" title="永久链接至目标">¶</a></dt>
<dd><p>返回用户本身就自带的权限字符串集合。</p>
<p>如果传入了 <code class="docutils literal notranslate"><span class="pre">obj</span></code> ，则只返回指定对象的用户权限。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.PermissionsMixin.get_group_permissions">
<code class="descname">get_group_permissions</code>(<em>obj=None</em>)<a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin.get_group_permissions" title="永久链接至目标">¶</a></dt>
<dd><p>返回用户拥有权限的字符串集合，从用户所属组的权限中获取。</p>
<p>如果传入 <code class="docutils literal notranslate"><span class="pre">obj</span></code>&nbsp;参数，则只返回指定对象所属组的权限。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.PermissionsMixin.get_all_permissions">
<code class="descname">get_all_permissions</code>(<em>obj=None</em>)<a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin.get_all_permissions" title="永久链接至目标">¶</a></dt>
<dd><p>返回用户拥有权限的字符串集合，同时从用户所属组及用户本身的权限中获取。</p>
<p>如果传入 <a href="#id1"><span class="problematic" id="id2">``</span></a>obj``参数，则只返回指定对象和所属组的权限。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.PermissionsMixin.has_perm">
<code class="descname">has_perm</code>(<em>perm</em>, <em>obj=None</em>)<a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin.has_perm" title="永久链接至目标">¶</a></dt>
<dd><p>如果用户具有指定的权限，则返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> ，其中 <code class="docutils literal notranslate"><span class="pre">perm</span></code> 的格式为 <code class="docutils literal notranslate"><span class="pre">&quot;&lt;app</span> <span class="pre">label&gt;.&lt;permission</span> <span class="pre">codename&gt;&quot;</span></code> (see <a class="reference internal" href="default.html#topic-authorization"><span class="std std-ref">permissions</span></a>)。如果 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_active" title="django.contrib.auth.models.User.is_active"><code class="xref py py-attr docutils literal notranslate"><span class="pre">User.is_active</span></code></a> 和 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_superuser" title="django.contrib.auth.models.User.is_superuser"><code class="xref py py-attr docutils literal notranslate"><span class="pre">is_superuser</span></code></a> 都为 <code class="docutils literal notranslate"><span class="pre">True</span></code>，则这个方法一直返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。</p>
<p>如果传入 <code class="docutils literal notranslate"><span class="pre">obj</span></code>&nbsp;参数，则这个方法不会检查该模型权限，而只会检查这个出传入对象的权限。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.PermissionsMixin.has_perms">
<code class="descname">has_perms</code>(<em>perm_list</em>, <em>obj=None</em>)<a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin.has_perms" title="永久链接至目标">¶</a></dt>
<dd><p>如果用户具有指定权限列表里的每个权限，则返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> ，其中perm的格式为 <code class="docutils literal notranslate"><span class="pre">&quot;&lt;app</span> <span class="pre">label&gt;.&lt;permission</span> <span class="pre">codename&gt;&quot;</span></code> 。如果 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_active" title="django.contrib.auth.models.User.is_active"><code class="xref py py-attr docutils literal notranslate"><span class="pre">User.is_active</span></code></a> 和 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_superuser" title="django.contrib.auth.models.User.is_superuser"><code class="xref py py-attr docutils literal notranslate"><span class="pre">is_superuser</span></code></a> 都返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> ，则这个方法一直返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。</p>
<p>如果传入参数  <code class="docutils literal notranslate"><span class="pre">obj</span></code>&nbsp; ，则这个方法不会检查指定的权限列表，只检查指定对象的权限。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.auth.models.PermissionsMixin.has_module_perms">
<code class="descname">has_module_perms</code>(<em>package_name</em>)<a class="headerlink" href="#django.contrib.auth.models.PermissionsMixin.has_module_perms" title="永久链接至目标">¶</a></dt>
<dd><p>如果用户拥有所给的 Django app 标签 (the Django app label) 里的任何权限，则会返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>&nbsp;。如果 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_active" title="django.contrib.auth.models.User.is_active"><code class="xref py py-attr docutils literal notranslate"><span class="pre">User.is_active</span></code></a> 和 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User.is_superuser" title="django.contrib.auth.models.User.is_superuser"><code class="xref py py-attr docutils literal notranslate"><span class="pre">is_superuser</span></code></a> 都为 <code class="docutils literal notranslate"><span class="pre">True</span></code> ，则该方法一直返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。</p>
</dd></dl>

</dd></dl>

<div class="admonition-permissionsmixin-and-modelbackend admonition">
<p class="first admonition-title"><code class="docutils literal notranslate"><span class="pre">PermissionsMixin</span></code>  和  <code class="docutils literal notranslate"><span class="pre">ModelBackend</span></code></p>
<p class="last">如果你没有引入 <a class="reference internal" href="#django.contrib.auth.models.PermissionsMixin" title="django.contrib.auth.models.PermissionsMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">PermissionsMixin</span></code></a> ，必须确保没有调用 <code class="docutils literal notranslate"><span class="pre">ModelBackend</span></code> 的权限方法。<code class="docutils literal notranslate"><span class="pre">ModelBackend</span></code> 假定你的用户模型某些字段可用。如果你的用户模型没有提供这些字段，则当你检查权限的时候，会收到数据库错误提示。</p>
</div>
</div>
<div class="section" id="s-custom-users-and-proxy-models">
<span id="custom-users-and-proxy-models"></span><h3>自定义用户和代理模型<a class="headerlink" href="#custom-users-and-proxy-models" title="永久链接至标题">¶</a></h3>
<p>自定义用户模型的一个限制是安装自定义用户模型将破坏任何扩展  <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 的代理模型。代理模型必须基于具体的基类；通过定义自定义用户模型，你就移除了Django可靠地识别基类的功能。</p>
<p>如果你的项目正在使用代理模型，你必须修改扩展用户模型的代理，或者把代理的行为都合并到 <a class="reference internal" href="../../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a> 子类里去。</p>
</div>
<div class="section" id="s-a-full-example">
<span id="s-custom-users-admin-full-example"></span><span id="a-full-example"></span><span id="custom-users-admin-full-example"></span><h3>一个完整的例子<a class="headerlink" href="#a-full-example" title="永久链接至标题">¶</a></h3>
<p>这里是一个兼容admin的自定义的用户app的例子。这个用户模型使用 email 地址作为username，并且生日是必填字段；除了用户账户上的 <code class="docutils literal notranslate"><span class="pre">admin</span></code> flag之外，它本身不提供权限检查。除用户创建的表单外，此模型和所有内置的身份验证表单和视图兼容。此例只是说明了大多数组件如何协同工作，不要直接复制到生产环境里。</p>
<p>这段代码将一直存在于 <code class="docutils literal notranslate"><span class="pre">models.py</span></code> 文件中，用于自定义身份验证 app:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="p">(</span>
    <span class="n">BaseUserManager</span><span class="p">,</span> <span class="n">AbstractBaseUser</span>
<span class="p">)</span>


<span class="k">class</span> <span class="nc">MyUserManager</span><span class="p">(</span><span class="n">BaseUserManager</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">create_user</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">date_of_birth</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Creates and saves a User with the given email, date of</span>
<span class="sd">        birth and password.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">email</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Users must have an email address&#39;</span><span class="p">)</span>

        <span class="n">user</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="p">(</span>
            <span class="n">email</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">normalize_email</span><span class="p">(</span><span class="n">email</span><span class="p">),</span>
            <span class="n">date_of_birth</span><span class="o">=</span><span class="n">date_of_birth</span><span class="p">,</span>
        <span class="p">)</span>

        <span class="n">user</span><span class="o">.</span><span class="n">set_password</span><span class="p">(</span><span class="n">password</span><span class="p">)</span>
        <span class="n">user</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">using</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">user</span>

    <span class="k">def</span> <span class="nf">create_superuser</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">date_of_birth</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Creates and saves a superuser with the given email, date of</span>
<span class="sd">        birth and password.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">user</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_user</span><span class="p">(</span>
            <span class="n">email</span><span class="p">,</span>
            <span class="n">password</span><span class="o">=</span><span class="n">password</span><span class="p">,</span>
            <span class="n">date_of_birth</span><span class="o">=</span><span class="n">date_of_birth</span><span class="p">,</span>
        <span class="p">)</span>
        <span class="n">user</span><span class="o">.</span><span class="n">is_admin</span> <span class="o">=</span> <span class="kc">True</span>
        <span class="n">user</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">using</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">user</span>


<span class="k">class</span> <span class="nc">MyUser</span><span class="p">(</span><span class="n">AbstractBaseUser</span><span class="p">):</span>
    <span class="n">email</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">EmailField</span><span class="p">(</span>
        <span class="n">verbose_name</span><span class="o">=</span><span class="s1">&#39;email address&#39;</span><span class="p">,</span>
        <span class="n">max_length</span><span class="o">=</span><span class="mi">255</span><span class="p">,</span>
        <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="n">date_of_birth</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">()</span>
    <span class="n">is_active</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
    <span class="n">is_admin</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>

    <span class="n">objects</span> <span class="o">=</span> <span class="n">MyUserManager</span><span class="p">()</span>

    <span class="n">USERNAME_FIELD</span> <span class="o">=</span> <span class="s1">&#39;email&#39;</span>
    <span class="n">REQUIRED_FIELDS</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;date_of_birth&#39;</span><span class="p">]</span>

    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">email</span>

    <span class="k">def</span> <span class="nf">has_perm</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">perm</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="s2">&quot;Does the user have a specific permission?&quot;</span>
        <span class="c1"># Simplest possible answer: Yes, always</span>
        <span class="k">return</span> <span class="kc">True</span>

    <span class="k">def</span> <span class="nf">has_module_perms</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app_label</span><span class="p">):</span>
        <span class="s2">&quot;Does the user have permissions to view the app `app_label`?&quot;</span>
        <span class="c1"># Simplest possible answer: Yes, always</span>
        <span class="k">return</span> <span class="kc">True</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">is_staff</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s2">&quot;Is the user a member of staff?&quot;</span>
        <span class="c1"># Simplest possible answer: All admins are staff</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_admin</span>
</pre></div>
</div>
<p>然后，在 Django 管理后台里注册这个用户模型，下面这些代码必须在 app 的 <code class="docutils literal notranslate"><span class="pre">admin.py</span></code> 文件里：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">Group</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.admin</span> <span class="kn">import</span> <span class="n">UserAdmin</span> <span class="k">as</span> <span class="n">BaseUserAdmin</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.forms</span> <span class="kn">import</span> <span class="n">ReadOnlyPasswordHashField</span>
<span class="kn">from</span> <span class="nn">django.core.exceptions</span> <span class="kn">import</span> <span class="n">ValidationError</span>

<span class="kn">from</span> <span class="nn">customauth.models</span> <span class="kn">import</span> <span class="n">MyUser</span>


<span class="k">class</span> <span class="nc">UserCreationForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;A form for creating new users. Includes all the required</span>
<span class="sd">    fields, plus a repeated password.&quot;&quot;&quot;</span>
    <span class="n">password1</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">&#39;Password&#39;</span><span class="p">,</span> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">PasswordInput</span><span class="p">)</span>
    <span class="n">password2</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">&#39;Password confirmation&#39;</span><span class="p">,</span> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">PasswordInput</span><span class="p">)</span>

    <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
        <span class="n">model</span> <span class="o">=</span> <span class="n">MyUser</span>
        <span class="n">fields</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="s1">&#39;date_of_birth&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">clean_password2</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c1"># Check that the two password entries match</span>
        <span class="n">password1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;password1&quot;</span><span class="p">)</span>
        <span class="n">password2</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;password2&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">password1</span> <span class="ow">and</span> <span class="n">password2</span> <span class="ow">and</span> <span class="n">password1</span> <span class="o">!=</span> <span class="n">password2</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="s2">&quot;Passwords don&#39;t match&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">password2</span>

    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
        <span class="c1"># Save the provided password in hashed format</span>
        <span class="n">user</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">commit</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
        <span class="n">user</span><span class="o">.</span><span class="n">set_password</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s2">&quot;password1&quot;</span><span class="p">])</span>
        <span class="k">if</span> <span class="n">commit</span><span class="p">:</span>
            <span class="n">user</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">user</span>


<span class="k">class</span> <span class="nc">UserChangeForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;A form for updating users. Includes all the fields on</span>
<span class="sd">    the user, but replaces the password field with admin&#39;s</span>
<span class="sd">    disabled password hash display field.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">password</span> <span class="o">=</span> <span class="n">ReadOnlyPasswordHashField</span><span class="p">()</span>

    <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
        <span class="n">model</span> <span class="o">=</span> <span class="n">MyUser</span>
        <span class="n">fields</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="s1">&#39;password&#39;</span><span class="p">,</span> <span class="s1">&#39;date_of_birth&#39;</span><span class="p">,</span> <span class="s1">&#39;is_active&#39;</span><span class="p">,</span> <span class="s1">&#39;is_admin&#39;</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">UserAdmin</span><span class="p">(</span><span class="n">BaseUserAdmin</span><span class="p">):</span>
    <span class="c1"># The forms to add and change user instances</span>
    <span class="n">form</span> <span class="o">=</span> <span class="n">UserChangeForm</span>
    <span class="n">add_form</span> <span class="o">=</span> <span class="n">UserCreationForm</span>

    <span class="c1"># The fields to be used in displaying the User model.</span>
    <span class="c1"># These override the definitions on the base UserAdmin</span>
    <span class="c1"># that reference specific fields on auth.User.</span>
    <span class="n">list_display</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="s1">&#39;date_of_birth&#39;</span><span class="p">,</span> <span class="s1">&#39;is_admin&#39;</span><span class="p">)</span>
    <span class="n">list_filter</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;is_admin&#39;</span><span class="p">,)</span>
    <span class="n">fieldsets</span> <span class="o">=</span> <span class="p">(</span>
        <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="s1">&#39;password&#39;</span><span class="p">)}),</span>
        <span class="p">(</span><span class="s1">&#39;Personal info&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;date_of_birth&#39;</span><span class="p">,)}),</span>
        <span class="p">(</span><span class="s1">&#39;Permissions&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;is_admin&#39;</span><span class="p">,)}),</span>
    <span class="p">)</span>
    <span class="c1"># add_fieldsets is not a standard ModelAdmin attribute. UserAdmin</span>
    <span class="c1"># overrides get_fieldsets to use this attribute when creating a user.</span>
    <span class="n">add_fieldsets</span> <span class="o">=</span> <span class="p">(</span>
        <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="p">{</span>
            <span class="s1">&#39;classes&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;wide&#39;</span><span class="p">,),</span>
            <span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="s1">&#39;date_of_birth&#39;</span><span class="p">,</span> <span class="s1">&#39;password1&#39;</span><span class="p">,</span> <span class="s1">&#39;password2&#39;</span><span class="p">),</span>
        <span class="p">}),</span>
    <span class="p">)</span>
    <span class="n">search_fields</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,)</span>
    <span class="n">ordering</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,)</span>
    <span class="n">filter_horizontal</span> <span class="o">=</span> <span class="p">()</span>


<span class="c1"># Now register the new UserAdmin...</span>
<span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">MyUser</span><span class="p">,</span> <span class="n">UserAdmin</span><span class="p">)</span>
<span class="c1"># ... and, since we&#39;re not using Django&#39;s built-in permissions,</span>
<span class="c1"># unregister the Group model from admin.</span>
<span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">unregister</span><span class="p">(</span><span class="n">Group</span><span class="p">)</span>
</pre></div>
</div>
<p>最后，在项目配置文件中的 <a class="reference internal" href="../../ref/settings.html#std:setting-AUTH_USER_MODEL"><code class="xref std std-setting docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a> 里指定自定义的用户模型为默认的用户模型。</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">AUTH_USER_MODEL</span> <span class="o">=</span> <span class="s1">&#39;customauth.MyUser&#39;</span>
</pre></div>
</div>
<div class="versionchanged">
<span class="title">Changed in Django 3.2:</span> <p>在旧版本中，<code class="docutils literal notranslate"><span class="pre">ReadOnlyPasswordHashField</span></code> 默认不是 <a class="reference internal" href="../../ref/forms/fields.html#django.forms.Field.disabled" title="django.forms.Field.disabled"><code class="xref py py-attr docutils literal notranslate"><span class="pre">disabled</span></code></a>，<code class="docutils literal notranslate"><span class="pre">UserChangeForm.clean_password()</span></code> 需要返回初始值，不管用户提供什么。</p>
</div>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">Django 中的自定义验证</a><ul>
<li><a class="reference internal" href="#other-authentication-sources">其它认证资源</a><ul>
<li><a class="reference internal" href="#specifying-authentication-backends">指定认证后端</a></li>
<li><a class="reference internal" href="#writing-an-authentication-backend">编写一个认证后端</a></li>
<li><a class="reference internal" href="#handling-authorization-in-custom-backends">在自定义后端处理认证</a><ul>
<li><a class="reference internal" href="#authorization-for-anonymous-users">匿名用户的授权</a></li>
<li><a class="reference internal" href="#authorization-for-inactive-users">非激活用户认证</a></li>
<li><a class="reference internal" href="#handling-object-permissions">处理对象权限</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#custom-permissions">自定义权限</a></li>
<li><a class="reference internal" href="#extending-the-existing-user-model">扩展现有的 <code class="docutils literal notranslate"><span class="pre">User</span></code> 模型</a></li>
<li><a class="reference internal" href="#substituting-a-custom-user-model">替换一个自定义的 <code class="docutils literal notranslate"><span class="pre">User</span></code> 模型。</a><ul>
<li><a class="reference internal" href="#using-a-custom-user-model-when-starting-a-project">启动项目时使用自定义用户模型</a></li>
<li><a class="reference internal" href="#changing-to-a-custom-user-model-mid-project">在项目中更改为自定义用户模型。</a></li>
<li><a class="reference internal" href="#reusable-apps-and-auth-user-model">可重用应用和 <code class="docutils literal notranslate"><span class="pre">AUTH_USER_MODEL</span></code></a></li>
<li><a class="reference internal" href="#referencing-the-user-model">引用 <code class="docutils literal notranslate"><span class="pre">User</span></code> 模型</a></li>
<li><a class="reference internal" href="#specifying-a-custom-user-model">指定自定义用户模型</a></li>
<li><a class="reference internal" href="#writing-a-manager-for-a-custom-user-model">为自定义的用户模型编写一个管理器</a></li>
<li><a class="reference internal" href="#extending-django-s-default-user">扩展Django的默认用户模型</a></li>
<li><a class="reference internal" href="#custom-users-and-the-built-in-auth-forms">自定义用户和内建的auth表单</a></li>
<li><a class="reference internal" href="#custom-users-and-django-contrib-admin">自定义用户和 <code class="docutils literal notranslate"><span class="pre">django.contrib.admin</span></code></a></li>
<li><a class="reference internal" href="#custom-users-and-permissions">自定义用户和权限。</a></li>
<li><a class="reference internal" href="#custom-users-and-proxy-models">自定义用户和代理模型</a></li>
<li><a class="reference internal" href="#a-full-example">一个完整的例子</a></li>
</ul>
</li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="passwords.html"
                        title="上一章">Django中的密码管理</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="../cache.html"
                        title="下一章">Django 缓存框架</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../../_sources/topics/auth/customizing.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="passwords.html" title="Django中的密码管理">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="../cache.html" title="Django 缓存框架">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>